#pragma once
#include <iostream>
#include "utility/index.hpp"
#include "request_access/index.hpp"
#include "data_access/index.hpp"
#include "components/index.hpp"

using namespace std;
using namespace utility;

namespace components2 {
    class Actions {
    public:
        static bool InsertStatusReview(const shared_ptr<components::EntityRequest> &e, int status, int dataType, const any &dataId, const string &remark);

        static bool UpdateSaleStatus(const shared_ptr<components::EntityRequest> &e, const any &saleOrderId);

        static bool UpdateProduceStatus(const shared_ptr<components::EntityRequest> &e, const any &saleOrderId);

        static bool UpdatePurchaseStatus(const shared_ptr<components::EntityRequest> &e, const any &purchaseOrderId);

        static void UpdateOrderCode(const shared_ptr<components::EntityRequest> &e, int type, const any &dataId);

        static void SetCancelReviewEntityData(const shared_ptr<components::EntityRequest> &e);

        static any Insert2(const shared_ptr<components::EntityRequest> &e, int dataType);

        static bool UpdateStatusAndReview(const shared_ptr<components::EntityRequest> &e, const EntityType *nextEntity, const EntityData &dict, int dataType);

        static void QueryAmountGroupByInfo(const shared_ptr<components::EntityRequest> &e, EntityData &data, const string &selectSql, const string &whereSql, const shared_ptr<data_access::DataParameters> &parameters);
    };

    void Actions::SetCancelReviewEntityData(const shared_ptr<components::EntityRequest> &e) {
        EntityData data;
        data["Status"] = 0;
        data["Remark"] = "撤回审核";
        data["RowVersion"] = e->Request->GetParameterValue("RowVersion");
        e->Request->RequestEntity[e->Entity->Name] = data;
    }

    void Actions::UpdateOrderCode(const shared_ptr<components::EntityRequest> &e, int type, const any &dataId) {
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@t", type);
        parameters->Add("@id", dataId);
        e->DataBase->Execute("call p_updateOrderCode(@t,@id)", parameters);
    }

    bool Actions::InsertStatusReview(const shared_ptr<components::EntityRequest> &e, int status, int dataType, const any &dataId, const string &remark) {
        auto statusReviewEntity = entity_access::GetEntityType("StatusReview");
        string actionName;
        if (status == 2) actionName = "审核通过";
        else if (status == 1) actionName = "审核不通过";
        else if (status == 0) actionName = "撤回";

        if (dataType == 7) {
            if (status == 3) actionName = "撤回完成";
            else if (status == 4) actionName = "安装完成";
        }

        EntityData entityData;
        entityData["Status"] = status;
        entityData["ActionName"] = actionName;
        entityData["DataId"] = dataId;
        entityData["DataType"] = dataType;
        entityData["Remark"] = remark;
        entityData["CreateUser"] = e->Request->OperationUser;

        return e->InsertEntity(statusReviewEntity, entityData);
    }

    bool Actions::UpdateSaleStatus(const shared_ptr<components::EntityRequest> &e, const any &saleOrderId) {
        auto saleOrderEntity = entity_access::GetEntityType("SaleOrder");
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@SaleOrderId", saleOrderId);
        string sql = "select fn_getSaleOrderStatus(@SaleOrderId) Status from dual";

        auto data = e->DataBase->Query(sql, parameters);
        if (data.empty()) return false;

        auto status = data[0].GetInt("Status");
        EntityData saleOrder;
        saleOrder["Status"] = status;

        return e->UpdateEntity(saleOrderEntity, e->GetQueryByPrimaryKey(saleOrderEntity, saleOrderId), saleOrder);
    }

    bool Actions::UpdateProduceStatus(const shared_ptr<components::EntityRequest> &e, const any &saleOrderId) {
        auto produceOrderEntity = entity_access::GetEntityType("ProduceOrder");
        auto productCompleteOrderEntity = entity_access::GetEntityType("ProductCompleteOrder");
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@SaleOrderId", saleOrderId);
        string sql = "select fn_getProduceOrderStatus(@SaleOrderId) Status from dual";

        auto data = e->DataBase->Query(sql, parameters);
        if (data.empty()) return false;

        auto status = data[0].GetInt("Status");
        EntityData entityData;
        entityData["Status"] = status;

        if (status == 4) {
            auto query = make_shared<data_access::Query>(productCompleteOrderEntity->TableName);
            query->Select("max(CompleteDate) CompleteDate");
            query->Where("where IsDelete=0 and SaleOrderId=@SaleOrderId", parameters);
            auto completeOrder = e->SelectEntity(query);

            if (!completeOrder.Empty()) entityData["RealCompleteDate"] = completeOrder.Get("CompleteDate");
        }

        return e->UpdateEntity(produceOrderEntity, e->GetQueryByName(produceOrderEntity, "SaleOrderId", saleOrderId), entityData);
    }

    bool Actions::UpdatePurchaseStatus(const shared_ptr<components::EntityRequest> &e, const any &purchaseOrderId) {
        auto purchaseOrderEntity = entity_access::GetEntityType("PurchaseOrder");
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@PurchaseOrderId", purchaseOrderId);
        string sql = "select fn_getPurchaseOrderStatus(@PurchaseOrderId) Status from dual";

        auto data = e->DataBase->Query(sql, parameters);
        if (data.empty()) return false;

        auto status = data[0].GetInt("Status");
        EntityData entityData;
        entityData["Status"] = status;

        return e->UpdateEntity(purchaseOrderEntity, e->GetQueryByPrimaryKey(purchaseOrderEntity, purchaseOrderId), entityData);
    }

    bool Actions::UpdateStatusAndReview(const shared_ptr<components::EntityRequest> &e, const EntityType *nextEntity, const EntityData &dict, int dataType) {
        EntityData entityData;

        auto status = dict.GetInt("Status");

        entityData["Status"] = status;

        if (dataType == 7) entityData["CompleteDate"] = dict.Get("CompleteDate");

        bool blSucceed = e->UpdateEntityByPrimaryKey(e->QueryRequest->PrimaryKeyValue, entityData);
        if (blSucceed) blSucceed = InsertStatusReview(e, status, dataType, e->QueryRequest->PrimaryKeyValue, dict.GetString("Remark"));

        if (blSucceed && status == 0 && nextEntity != nullptr) e->DeleteEntityByLogic(nextEntity, e->Entity->PrimaryKey, e->QueryRequest->PrimaryKeyValue);

        return blSucceed;
    }

    any Actions::Insert2(const shared_ptr<components::EntityRequest> &e, int dataType) {
        EntityData entityData = e->Request->RequestEntity.GetEntityData(e->Entity->Name);
        e->AddCreateUser(entityData);

        bool blSucceed = true;
        try {
            e->DataBase->BeginTransaction();

            blSucceed = e->InsertEntity(entityData);
            if (blSucceed) blSucceed = components::EntityByComplexTypeOperation::EditDeleteComplexType(e, entityData, false);

            if (blSucceed) UpdateOrderCode(e, dataType, entityData.Get(e->Entity->PrimaryKey));

            if (blSucceed) e->DataBase->CommitTransaction();
            else e->DataBase->RollbackTransaction();

            auto obj = e->GetSucceedMap(blSucceed);
            if (blSucceed)obj[e->Entity->PrimaryKey] = entityData[e->Entity->PrimaryKey];

            return  obj;
        }
        catch (const exception &ex) {
            e->DataBase->RollbackTransaction();
            throw MessageException(ex.what(), "Actions::Insert2");
        }
    }

    void Actions::QueryAmountGroupByInfo(const shared_ptr<components::EntityRequest> &e, EntityData &data, const string &selectSql, const string &whereSql, const shared_ptr<data_access::DataParameters> &parameters) {
        auto query = make_shared<data_access::Query>(e->Entity->TableName);
        query->Select(selectSql);
        query->Where(whereSql, parameters);

        auto entityData = e->SelectEntity(query);

        for (const auto &kvp: entityData.ToMap()) {
            data[kvp.first] = kvp.second;
        }
    }
}
